package algorithm.practice.Test;

import java.util.Arrays;
import java.util.Random;

import algorithm.practice.Impl.SortingImpl;
import algorithm.practice.Itf.SortingInterface;

public class SortingTest {
	private static final int MIN_ARRAY_SIZE = 2;
	private static final int MAX_ARRAY_SIZE = 1000;
	private static final int RANDOM_NUM_START = 1;
	private static final int RANDOM_NUM_END = 100000;
	private static int num_testcases = 2;

	public static void main(String args[]) {
		SortingInterface sort = new SortingImpl();
		sortTest(sort);
	}

	/**
	 * @param Object
	 *            of type SortingInterface
	 */
	private static void sortTest(SortingInterface sort) {
		int[] numberArray;
		while (num_testcases-- > 0) {
			numberArray = setUpArray();
			int[] copyNumberArray = Arrays.copyOf(numberArray,
					numberArray.length);
			insertionSortTest(sort, numberArray);
			nativeSortTest(copyNumberArray);
			compareSort(numberArray, copyNumberArray);
		}
	}

	/**
	 * @param numberArray
	 *            of insertion sort
	 * @param copyNumberArray
	 *            of native sort 
	 * Compare insertion sort and native sort result
	 */
	private static void compareSort(int[] numberArray, int[] copyNumberArray) {
		if (numberArray.length != copyNumberArray.length) {
			System.out
					.println("Insertion sort array size is less than Native sort array");
			return;
		} else {
			for (int i = 0; i < copyNumberArray.length; i++) {
				if (numberArray[i] != copyNumberArray[i]) {
					System.out.println("Insertion sort is not correct");
					return;
				}
			}
			System.out.println("Insertion and Native sort array are same");
		}
	}

	/**
	 * @param unsorted
	 *            integer copyNumberArray 
	 * Sorting an array using native sort method and calculating its time
	 */
	private static void nativeSortTest(int[] copyNumberArray) {
		long standardSortStartTime = System.nanoTime();
		Arrays.sort(copyNumberArray);
		long standardSortStopTime = System.nanoTime();
		long standardSortElapsedTime = standardSortStopTime
				- standardSortStartTime;
		System.out.println("Native Sort time on testcase " + num_testcases
				+ " : " + standardSortElapsedTime + " nsec");

	}

	/**
	 * @param sort
	 *            object of type SortingIterface
	 * @param unsorted
	 *            integer numberArray 
	 * Sorting an array using Insertion sort and calculating its time
	 */
	private static void insertionSortTest(SortingInterface sort,
			int[] numberArray) {
		// Calculate insertion sorting time
		long insertionStartTime = System.nanoTime();
		sort.insertionSort(numberArray);
		long insertionStopTime = System.nanoTime();
		long insertionElapsedTime = insertionStopTime - insertionStartTime;
		System.out.println("Insertion sort time on testcase " + num_testcases
				+ " : " + insertionElapsedTime + " nsec");

	}

	//
	/**
	 * @return an integer array 
	 * Initialize integer array of random size with randomly generated value which needs to be sorted
	 */
	private static int[] setUpArray() {
		int[] numbers;
		Random rand = new Random();
		int arraySize = rand.nextInt(MAX_ARRAY_SIZE) + MIN_ARRAY_SIZE;
		numbers = new int[arraySize];
		for (int i = 0; i < numbers.length; i++) {
			numbers[i] = generateRandomIntegers(RANDOM_NUM_START,
					RANDOM_NUM_END, rand);
		}
		return numbers;
	}

	/**
	 * @param start of random number
	 * @param end limit of random number
	 * @param random object of class Random
	 * @return a randomly generates integer
	 */
	private static int generateRandomIntegers(int start, int end, Random random) {
		int range = (end - start) + 1;
		int fraction = (int) (range * random.nextDouble());
		int randomNumer = fraction + start;
		return randomNumer;
	}
}
